<?php
/**
 * Created by PhpStorm.
 * User: xiaosq
 * Date: 2018/6/20
 * Time: 18:21
 */

namespace App\Http\Controllers\Admin\Meeting;

use App\Http\Controllers\Admin\AdminController;
use App\Models\Material;
use App\Models\Meeting;
use App\Models\MeetingUser;
use Illuminate\Http\Request;
use App\Api\Exceptions\ApiCommonException;
use Illuminate\Support\Facades\DB;
use Storage;
use Validator;
use Lang;
use App\Handlers\Oss;
use App\Handlers\Face;
use Illuminate\Validation\Rule;
use Maatwebsite\Excel\Excel;

class UsersController extends AdminController
{
    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request, $meeting_id, MeetingUser $meetingUser)
    {
        $per_page = $request->input('per_page', $this->per_page);
        $real_name = $request->real_name;

        $current_query = $meetingUser->select('id', 'real_name', 'mobile', 'face_image', 'tag', 'status', 'sign_in_at')->where('meeting_id', $meeting_id);

        if (!empty($real_name)) {
            $current_query->where('real_name', 'like', '%'.$real_name.'%');
        }

        $data = $current_query->orderBy('updated_at', 'DESC')->paginate($per_page);

        if (!empty($data)) {
            foreach ($data as $key => $val) {
                $face_image = $val->face_image;
                $data[$key]['face_image_url'] = '';
                if (!empty($face_image)) {
                    $data[$key]['face_image_url'] = Oss::getPublicObjectURL($face_image);
                }
            }
        }

        return $this->getResponseSuccess($data);
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function store(Request $request, $meeting_id, MeetingUser $meetingUser)
    {
        // 创建验证规则
        $rules = [
            'real_name' => 'bail|required|max:10',
            'mobile' => [
                'bail',
                'required',
                'regex:/^1[34578][0-9]{9}$/',
                Rule::unique('meeting_users')->where(function ($query) use($meeting_id){
                    $query->where('meeting_id', $meeting_id)->whereNull('deleted_at');
                }),
            ],
            'face_image' => 'required',
        ];

        // 自定义验证消息
        $messages = [
            'real_name.required' => Lang::get('meeting_user.real_name').Lang::get('common.required'),
            'real_name.max' => Lang::get('meeting_user.real_name').Lang::get('common.max'),
            'mobile.required' => Lang::get('meeting_user.mobile').Lang::get('common.required'),
            'mobile.regex' => Lang::get('common.mobile_regex'),
            'mobile.unique' => Lang::get('meeting_user.mobile').Lang::get('common.unique'),
            'face_image.required' => Lang::get('meeting_user.face_image').Lang::get('common.required'),
        ];

        //开始验证
        $validator = Validator::make($request->all(), $rules, $messages);


        if($validator->fails())
        {
            throw ApiCommonException::requestParamsErr($validator->messages()->first());
        }

        $data = $request->all();
        $data['meeting_id'] = $meeting_id;
        $data['status'] = 1;

        $meetingUser->fill($data);

        //事物开始
        DB::beginTransaction();

        $r = $meetingUser->save();

        if (!$r) {
            //事物回滚
            DB::rollBack();
            throw ApiCommonException::requestParamsErr(Lang::get('common.action_error'));
        }

        $person = $this->newPerson($meetingUser);

        if (!$person) {
            //事物回滚
            DB::rollBack();
            throw ApiCommonException::faceNewPersonErr();
        }

        $update_data['person_id'] = $person['person_id'];
        $update_data['person_session_id'] = $person['session_id'];
        $update_data['person_face_id'] = $person['face_id'];

        $r = MeetingUser::where('id', $meetingUser->id)->update($update_data);

        if (!$r) {
            //事物回滚
            DB::rollBack();
            throw ApiCommonException::requestParamsErr(Lang::get('common.action_error'));
        }

        Meeting::where('id', $meeting_id)->increment('sign_up_num', 1);

        //事物提交
        DB::commit();

        $meeting_info = Meeting::select('sign_up_num')->where('id', $meeting_id)->first();

        return $this->getResponseSuccess($meeting_info);
    }

    /**
     * Display the specified resource.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function show($meeting_id, $id)
    {
        $data = MeetingUser::select('id', 'real_name', 'mobile', 'face_image', 'tag',  'status')->find($id);

        if (!empty($data)) {
            $data->face_image_url = Oss::getPublicObjectURL($data->face_image);
        }

        return $this->getResponseSuccess($data);
    }

    /**
     * Update the specified resource in storage.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request, $meeting_id, $id)
    {
        // 创建验证规则
        $rules = [
            'real_name' => 'bail|required|max:10',
            'mobile' => 'bail|required|regex:/^1[34578][0-9]{9}$/',
            'mobile' => [
                'bail',
                'required',
                'regex:/^1[34578][0-9]{9}$/',
                Rule::unique('meeting_users')->ignore($id)->where(function ($query) use($meeting_id){
                    $query->where('meeting_id', $meeting_id)->whereNull('deleted_at');
                }),
            ],
            'face_image' => 'required',
        ];

        // 自定义验证消息
        $messages = [
            'real_name.required' => Lang::get('meeting_user.real_name').Lang::get('common.required'),
            'real_name.max' => Lang::get('meeting_user.real_name').Lang::get('common.max'),
            'mobile.required' => Lang::get('meeting_user.mobile').Lang::get('common.required'),
            'mobile.regex' => Lang::get('common.mobile_regex'),
            'mobile.unique' => Lang::get('meeting_user.mobile').Lang::get('common.unique'),
            'face_image.required' => Lang::get('meeting_user.face_image').Lang::get('common.required'),
        ];

        //开始验证
        $validator = Validator::make($request->all(), $rules, $messages);

        if($validator->fails())
        {
            throw ApiCommonException::requestParamsErr($validator->messages()->first());
        }

        MeetingUser::findOrFail($id)->update($request->all());

        return $this->getResponseSuccess();
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param  int  $id
     * @return \Illuminate\Http\Response
     */
    public function destroy($meeting_id, $id)
    {
        //查询会议状态
        $meeting_info = Meeting::select('sign_in_start_at')->where('id', $meeting_id)->first();

        $now = time();
        $sign_in_start_at_str = strtotime($meeting_info->sign_in_start_at);

        if ($now > $sign_in_start_at_str) {
            throw ApiCommonException::requestParamsErr(Lang::get('meeting_user.not_allow_del'));
        }

        $id = explode(",", $id);

        $count = MeetingUser::destroy($id);

        if (!$count) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.action_error'));
        }

        $c = 0;
        foreach ($id as $val) {
            $person_id = "person".$val;

            $face = new Face($person_id);

            $ret = $face->delPerson($person_id);
            if ($ret['errorcode'] == 0 && $ret['deleted'] == 1) {
                $c++;
            }
        }

        if ($c > 0) {
            Meeting::where('id', $meeting_id)->decrement('sign_up_num', $c);
        }

        $meeting_info = Meeting::select('sign_up_num')->where('id', $meeting_id)->first();

        return $this->getResponseSuccess($meeting_info);
    }

    /**
     * 会议用户导出
     * @param Request $request
     * @param $meeting_id
     * @param MeetingUser $meetingUser
     */
    public function export(Request $request, $meeting_id, Excel $excel)
    {
        $data = MeetingUser::select('id', 'real_name', 'mobile', 'face_image', 'tag', 'status', 'sign_in_at')->where('meeting_id', $meeting_id)->get();

        $cellData = $data->toArray();

        if (empty($cellData)) {
            throw ApiCommonException::dataIsEmpty();
        }

        foreach ($cellData as $key => $val) {
            $status = $val['status'];
            $status_text = '';
            switch ($status) {
                case 1:
                    $status_text = "已报名";
                    break;

                case 2:
                    $status_text = "已签到";
                    break;

                default:
                    $status_text = '';
                    break;
            }

            $cellData[$key]['status'] = $status_text;
            $cellData[$key]['face_image'] = Oss::getPublicObjectURL($val['face_image']);
        }

        $file_name = "meeting".$meeting_id.'_'.date('Ymd');

        $excel->create($file_name,function($excel) use ($cellData){
            $excel->sheet('score', function($sheet) use ($cellData){
                $header = ['序号', '姓名', '手机号', '人脸图片', '标签', '状态', '签到时间'];
                array_unshift($cellData, $header);

                $sheet->rows($cellData);
            });
        })->export('xls');
    }

    /**
     * 会议用户导入
     * @param Request $request
     * @param $meeting_id
     * @param Excel $excel
     * @return array
     */
    public function import(Request$request, $meeting_id, Excel $excel)
    {
        $file = $request->file('excel');

        // 创建验证规则
        $rules = [
            'excel'      => 'required',
        ];

        // 自定义验证消息
        $messages = [
            'excel.required'      => Lang::get('meeting_user.import_excel').Lang::get('common.required'),
        ];

        //开始验证
        $validator = Validator::make($request->all(), $rules, $messages);

        if($validator->fails())
        {
            throw ApiCommonException::requestParamsErr($validator->messages()->first());
        }

        $file_extension = strtolower($file->getClientOriginalExtension());
        $extension_allow = config('filesystems.excel_extension_allow');

        if (!in_array($file_extension, $extension_allow)) {
            throw ApiCommonException::requestParamsErr(Lang::get('material.media').Lang::get('common.not_extension'));
        }

        $file_size = $file->getClientSize();
        $max_file_size = config('filesystems.excel_max_size');

        if ($file_size > $max_file_size) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.file_max_size'));
        }

        $file = $file->storeAs('meeting', md5(uniqid(time())).'.xls');

        $real_path = storage_path('app/'.$file);

        $excel->load($real_path, function($reader) use($meeting_id, $file) {
            $import_data = $reader->all();

            if (empty($import_data)) {
                throw ApiCommonException::dataIsEmpty();
            }

            $data = $import_data->toArray();

            //过滤数组重复值
            $mobile_all = [];
            foreach ($data as $key => $val) {
                $mobile_all[$key] = $val['phone'];
            }

            if (count($mobile_all) != count(array_unique($mobile_all))) {
                Storage::delete($file);
                throw ApiCommonException::requestParamsErr(Lang::get('meeting_user.mobile_repeat'));
            }

            $save_data = [];
            foreach ($data as $key => $val) {
                $mobile = $val['phone'];
                //检测重复手机号
                $count = MeetingUser::where('meeting_id', $meeting_id)->where('mobile', $mobile)->count();

                if ($count > 0) {
                    Storage::delete($file);
                    throw ApiCommonException::requestParamsErr('手机号'.$mobile.'重复，请修改后重新导入！');
                }

                $save_data[$key]['real_name'] = isset($val['name'])?$val['name']:'';
                $save_data[$key]['meeting_id'] = $meeting_id;
                $save_data[$key]['mobile'] = isset($val['phone'])?$val['phone']:'';
                $save_data[$key]['status'] = 0;
                $save_data[$key]['tag'] = isset($val['label'])?$val['label']:'';
            }

            $r = MeetingUser::insert($save_data);

            if (!$r) {
                Storage::delete($file);
                throw ApiCommonException::requestParamsErr(Lang::get('common.action_error'));
            }
        });

        Storage::delete($file);

        $meeting_info = Meeting::select('sign_up_num')->where('id', $meeting_id)->first();

        return $this->getResponseSuccess($meeting_info);
    }

    /**
     * 添加人脸图片
     * @param Request $request
     * @param $meeting_id
     * @param MeetingUser $meetingUser
     * @param Material $material
     */
    public function faceImage(Request$request, $meeting_id, MeetingUser $meetingUser, Material $material)
    {
        $file = $request->file('media');
        $media_type = $request->input('media_type', 1);

        // 创建验证规则
        $rules = [
            'media'      => 'required',
        ];

        // 自定义验证消息
        $messages = [
            'media.required'      => Lang::get('material.media').Lang::get('common.required'),
        ];

        //开始验证
        $validator = Validator::make($request->all(), $rules, $messages);

        if($validator->fails())
        {
            throw ApiCommonException::requestParamsErr($validator->messages()->first());
        }

        //检测手机号是否存在
        $client_name = $file->getClientOriginalName();

        $image_arr = explode('.', $client_name);
        $mobile = $image_arr[0];

        $count = MeetingUser::where('meeting_id', $meeting_id)->where('mobile', $mobile)->count();

        if ($count == 0) {
            throw ApiCommonException::requestParamsErr('人脸图片'.$client_name.'对应的用户不存在，请先导入相应用户数据！');
        }

        $meeting_user_info = MeetingUser::select('face_image')->where('meeting_id', $meeting_id)->where('mobile', $mobile)->first();

        if (!empty($meeting_user_info->face_image)) {
            throw ApiCommonException::requestParamsErr(Lang::get('meeting_user.face_image_repeat'));
        }

        $file_extension = strtolower($file->getClientOriginalExtension());
        $options = [];

        switch ($media_type) {
            case 1:
                $extension_allow = config('filesystems.image_extension_allow');
                $max_file_size = config('filesystems.image_max_size');
                $options = ['ContentType'=>'image/'.$file_extension];
                break;

            case 4:
                $extension_allow = config('filesystems.file_extension_allow');
                $max_file_size = config('filesystems.file_max_size');
                break;

            default:
                $extension_allow = config('filesystems.image_extension_allow');
                $max_file_size = config('filesystems.image_max_size');
        }

        if (!in_array($file_extension, $extension_allow)) {
            throw ApiCommonException::requestParamsErr(Lang::get('material.media').Lang::get('common.not_extension'));
        }

        $file_size = $file->getClientSize();

        if ($file_size > $max_file_size) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.file_max_size'));
        }

        $file = $file->storeAs('media', md5(uniqid(time())).'.'.$file_extension);

        $exists = Storage::exists($file);

        if (!$exists) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.file_upload_exception'));
        }

        $real_path = storage_path('app/'.$file);

        $media_id = $file;

        OSS::publicUpload($media_id, $real_path, $options);

        //阿里 OSS 图片上传
        try {
            OSS::publicUpload($media_id, $real_path, $options);
        } catch (\Exception $e) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.oss_exception'));
        }

        $data['media_type'] = $media_type;
        $data['bucket_name'] = config('alioss.BucketName');
        $data['media_id'] = $media_id;

        $r = $material->create($data);

        if (!$r) {
            throw ApiCommonException::requestParamsErr(Lang::get('common.action_error'));
        }

        Storage::delete($file);

        //查询图片对应用户数据
        $meeting_user_info = $meetingUser->select('id', 'meeting_id', 'real_name', 'tag')->where('meeting_id', $meeting_id)->where('mobile', $mobile)->first();

        $meeting_user_info->face_image = $media_id;

        $person = $this->newPerson($meeting_user_info);

        if (!$person) {
            throw ApiCommonException::faceNewPersonErr($client_name);
        }

        $update_data['face_image'] = $media_id;
        $update_data['person_id'] = $person['person_id'];
        $update_data['person_session_id'] = $person['session_id'];
        $update_data['person_face_id'] = $person['face_id'];
        $update_data['status'] = 1;

        $r = MeetingUser::where('id', $meeting_user_info->id)->update($update_data);

        if (!$r) {
            throw ApiCommonException::requestParamsErr(Lang::get('meeting_user.update_person_error'));
        }

        Meeting::where('id', $meeting_id)->increment('sign_up_num', 1);

        return $this->getResponseSuccess();
    }

    /**
     * 腾讯优图新建用户
     * @param $user_info
     * @return bool|\TencentYoutuyun\返回的结果，JSON字符串，字段参见API文档
     */
    private function newPerson($user_info)
    {
        $url = Oss::getPublicObjectURL($user_info->face_image);
        $person_id = "person".$user_info->id;
        $group_ids = [(string)$user_info->meeting_id];
        $person_name = $user_info->real_name;
        $person_tag = $user_info->tag;

        $face = new Face($person_id);

        try {
            $ret = $face->newPersonUrl($url, $person_id, $group_ids, $person_name, $person_tag);
            if ($ret['errorcode'] != 0) {
                return false;
            }
        } catch (\Exception $e) {
            return false;
        }

        return $ret;
    }
}